#include "SpaceInvadersPCH.h"
#include "Game.h"
#include "AutoGen_RenderData.h"
#include "Player.h"
#include "Font.h"
#include "WeaponManager.h"

void Game::Run()
{
	gk::InitParams gkInitParams;
	gkInitParams.m_enableDebugging = true;
	gkInitParams.m_startVisible = true;
	gkInitParams.m_szTitle = "SpaceInvaders";
	gkInitParams.m_hDisplayConfigSelector = this;
	gk::Initialise(gkInitParams);
	
	// Initialise
	data::DataConfigs_LoadMemorySlotConfigsFromFile("../Common/SpaceInvaders/Configs/MemorySlotConfigs.xml", m_dataConfig.slotConfigs);
	data::DataConfigs_LoadDataBlockConfigsFromFile("../Common/SpaceInvaders/Configs/DataBlockConfigs.xml", m_dataConfig.dataBlockConfigs);
	data::Manager::Get().Initialise(m_dataConfig);
	data::Manager::Get().RegisterDataProcessor(&m_renderDataProcessor, shared::prehash::hs_RDAT);

	gk::RenderTarget systemRenderTarget;
	systemRenderTarget.m_hColourSurface[0] = gk::GetDevice()->GetBackBuffer();

	gk::RenderSurface depthSurface;
	depthSurface.m_format = gk::BufferFormat::D24S8;
	depthSurface.m_createTexture = false;
	depthSurface.m_width = systemRenderTarget.m_hColourSurface[0]->m_width;
	depthSurface.m_height = systemRenderTarget.m_hColourSurface[0]->m_height;
	depthSurface.m_multisampleType = systemRenderTarget.m_hColourSurface[0]->m_multisampleType;
	cr::ClearObject(depthSurface.m_multisampleType);
	gk::GetDevice()->CreateRenderSurface(depthSurface);
	systemRenderTarget.m_hDepthSurface = depthSurface;
	gk::GetDevice()->CreateRenderTarget(systemRenderTarget);

	// Setup default render-state
	gk::StateBlock defaultRenderState;
	cr::ClearObject(defaultRenderState);
	gk::GetDevice()->CreateStateBlock(defaultRenderState);
	defaultRenderState.SetDefault();
	defaultRenderState.GetStateValue(gk::RenderState::DepthTest).m_renderStateValue = gk::RenderStateValue::DepthTestEnabled;

	float aspectRatio = (float)depthSurface.m_width / (float)depthSurface.m_height;

	// Initialise game objects
	static Environment environment;
	environment.Initialise();

	static Player	player;
	player.Initialise();

	static Font font;
	font.Initialise(spaceinvaders::prehash::hs_FontTahoma);

	WeaponManager::Get().Initialise();

	// Loop
	do
	{
		environment.Step();
		player.Step();
		WeaponManager::Get().Step();

		gk::GetDevice()->GetSystemContext()->BeginFrame();
		gk::GetDevice()->GetSystemContext()->SetRenderTarget(systemRenderTarget);
		gk::GetDevice()->GetSystemContext()->ClearRenderTarget(gk::ClearType::All, 0.25f,0.3f,0.4f,0,1,0);

		{
			DrawContext drawContext;
			drawContext.SetContext(gk::GetDevice()->GetSystemContext());

			drawContext.GetContext()->CommitStateBlock(defaultRenderState);

			gp::ParameterBlockScratch<32> globalParams;
			
			static float camHeight = 46.0f;
			static float camDist = -117.0f;

			if (pf::GetPlatform()->GetKeyboard()->GetKeyDown(pf::KeyboardButton::Key_Numpad9))
				camHeight += 1.0f;
			if (pf::GetPlatform()->GetKeyboard()->GetKeyDown(pf::KeyboardButton::Key_Numpad7))
				camHeight -= 1.0f;
			if (pf::GetPlatform()->GetKeyboard()->GetKeyDown(pf::KeyboardButton::Key_Numpad8))
				camDist += 1.0f;
			if (pf::GetPlatform()->GetKeyboard()->GetKeyDown(pf::KeyboardButton::Key_Numpad2))
				camDist -= 1.0f;

			cr::Matrix4f worldToView, viewToScreen, worldToScreen, objectToWorld;
			objectToWorld = cr::Matrix4f::Identity;
			cr::Maths::SetPerspectiveProjectionFovLH(viewToScreen, cr::Maths::kPI/2.0f, aspectRatio, 0.1f, 1000.0f);
			cr::Maths::SetViewLookAt(worldToView, cr::Vec4f(0.0f, camHeight, camDist,1.0f), cr::Vec4f(0.0f,0.0f,0.0f,1.0f), cr::Vec4f::Yaxis);
			worldToScreen = viewToScreen*worldToView;

			cr::Vec4f lightDir(0,1,0,0);
			cr::Vec4f ambientLightColour(0.1f,0.1f,0.1f,0);

			globalParams.AddParameter()->Set(spaceinvaders::prehash::hs_g_worldToScreen, spaceinvaders::prehash::hs_WORLDTOSCREEN, gk::GpuProgramParameterType::Matrix, worldToScreen);
			globalParams.AddParameter()->Set(spaceinvaders::prehash::hs_g_objectToWorld, spaceinvaders::prehash::hs_OBJECTTOWORLD, gk::GpuProgramParameterType::Matrix, objectToWorld);
			globalParams.AddParameter()->Set(spaceinvaders::prehash::hs_g_Light_Direction, spaceinvaders::prehash::hs_g_Light_Direction, gk::GpuProgramParameterType::Vector, lightDir);
			globalParams.AddParameter()->Set(spaceinvaders::prehash::hs_g_Light_AmbientColour, spaceinvaders::prehash::hs_g_Light_AmbientColour, gk::GpuProgramParameterType::Vector, ambientLightColour);
			globalParams.AddParameter()->Set(spaceinvaders::prehash::hs_g_Light_DiffuseColour, spaceinvaders::prehash::hs_g_Light_DiffuseColour, gk::GpuProgramParameterType::Vector, cr::Vec4f::One);
			
			drawContext.GetContext()->CommitStateBlock(defaultRenderState);
			drawContext.PushParameterBlock(globalParams);
			font.Print("0123456789", 0,50.0f);
			environment.Draw(drawContext);
			player.Draw(drawContext);
			WeaponManager::Get().Draw(drawContext);
			drawContext.PopParameterBlock();
		}

		gk::GetDevice()->GetSystemContext()->EndFrame();
		data::Manager::Get().Step();
		gp::ParameterBlockScratchAllocator::ResetScratchParams();
	}
	while (gk::GetDevice()->Present());

	// Shutdown game objects
	WeaponManager::Get().Shutdown();
	font.Shutdown();
	player.Shutdown();
	environment.Shutdown();

	gk::GetDevice()->ReleaseStateBlock(defaultRenderState);
	gk::GetDevice()->ReleaseRenderTarget(systemRenderTarget);
	gk::GetDevice()->ReleaseRenderSurface(depthSurface);

	while (data::Manager::Get().Step());
	data::Manager::Get().UnregisterDataProcessor(&m_renderDataProcessor, shared::prehash::hs_RDAT);
	data::Manager::Get().Shutdown();

	// Shutdown
	gk::Shutdown();
}

pf::DisplayConfig* Game::ConfigureDisplay(pf::DisplayConfig* /*pConfig*/ ,cr::size_t /*numConfigs*/)
{
	// Because we are on a PC for now, I can select whatever I want!
	static pf::DisplayConfig displayConfig;
	displayConfig.m_width = 1920;
	displayConfig.m_height = 1080;
	return &displayConfig;
}